package com.atguigu.tingshu.order.strategy.impl;
import java.math.BigDecimal;
import java.util.Date;

import com.atguigu.tingshu.common.constant.KafkaConstant;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.google.common.collect.Maps;

import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.order.service.OrderDerateService;
import com.atguigu.tingshu.order.service.OrderDetailService;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.google.common.collect.Lists;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.order.strategy.SaveOrderStrategy;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class WeiXinSaveOrderStrategy implements SaveOrderStrategy {
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderDerateService orderDerateService;

    @Autowired
    RedissonClient redissonClient;

    //@Transactional
    @Override
    public OrderInfoVo saveOrder(OrderInfoVo orderInfoVo) {
        WeiXinSaveOrderStrategy weiXinSaveOrderStrategy = (WeiXinSaveOrderStrategy) AopContext.currentProxy();//获取代理对象
        weiXinSaveOrderStrategy.saveOrderAndDetailAndDerate(orderInfoVo);//目标对象的代理对象调用方法
        /**
         * 发布延迟消息 为了30分钟超时后若用户未支付则系统自动取消订单
         */
        this.sendDelayTask(orderInfoVo.getTradeNo());
        return orderInfoVo;
    }

    private void sendDelayTask(String tradeNo) {
        RBlockingDeque<String> blockingDeque = redissonClient.getBlockingDeque(RedisConstant.QUEUE_ORDER_CANCEL); //获得阻塞队列
        RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(blockingDeque); //获得延迟队列
        delayedQueue.offer(tradeNo,RedisConstant.DELAY_TIME, TimeUnit.SECONDS); //发布30分钟的延迟任务
    }

    @Transactional
    public void saveOrderAndDetailAndDerate(OrderInfoVo orderInfoVo) {
        Long userId = AuthContextHolder.getUserId();
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        String itemName = orderDetailVoList.get(0).getItemName();
        //保存订单的基本数据
        OrderInfo infoVo = new OrderInfo();
        infoVo.setUserId(userId);
        infoVo.setOrderTitle(itemName);
        infoVo.setOrderNo(orderInfoVo.getTradeNo());
        infoVo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        infoVo.setOriginalAmount(orderInfoVo.getOriginalAmount());
        infoVo.setDerateAmount(orderInfoVo.getDerateAmount());
        infoVo.setOrderAmount(orderInfoVo.getOrderAmount());
        infoVo.setItemType(orderInfoVo.getItemType());
        infoVo.setPayWay(orderInfoVo.getPayWay());
        orderInfoService.save(infoVo);

        //保存明细
        List<OrderDetail> orderDetailList = orderDetailVoList.stream().map(orderDetailVo -> {
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(infoVo.getId());
            orderDetail.setItemId(orderDetailVo.getItemId());
            orderDetail.setItemName(orderDetailVo.getItemName());
            orderDetail.setItemUrl(orderDetailVo.getItemUrl());
            orderDetail.setItemPrice(orderDetailVo.getItemPrice());
            return orderDetail;
        }).collect(Collectors.toList());
        orderDetailService.saveBatch(orderDetailList);

        //保存减免信息
        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        if (orderDerateVoList != null) {
            List<OrderDerate> orderDerateList = orderDerateVoList.stream().map(orderDerateVo -> {
                OrderDerate orderDerate = new OrderDerate();
                orderDerate.setOrderId(infoVo.getId());
                orderDerate.setDerateType(orderDerateVo.getDerateType());
                orderDerate.setDerateAmount(orderDerateVo.getDerateAmount());
                orderDerate.setRemarks(orderDerateVo.getRemarks());
                orderDerate.setId(0L);
                return orderDerate;
            }).collect(Collectors.toList());
            orderDerateService.saveBatch(orderDerateList);
        }
    }

    @Override
    public String getPayWay() {
        return SystemConstant.ORDER_PAY_WAY_WEIXIN;
    }
}
